#ifndef VARIABLE_H
#define VARIABLE_H
#include "interpreter.h"

class Variable {
public:
    Variable();
    /* initialize the variable system */
    static void VariableInit(Interpreter *pc);

    /* deallocate the contents of a variable */
    static void VariableFree(Interpreter *pc, Value *val);

    /* deallocate the global table and the string literal table */
    static void VariableTableCleanup(Interpreter *pc, Table *hashTable);

    static void VariableCleanup(Interpreter *pc);

    /* allocate some memory, either on the heap or the stack
        and check if we've run out */
    static void *VariableAlloc(Interpreter *pc, ParseState *parser, int size, int onHeap);

    /* allocate a Value either on the heap or the stack using space
        dependent on what type we want */
    static Value *VariableAllocValueAndData(Interpreter *pc, ParseState *parser, int dataSize,
                                            int isLValue, Value *lValueFrom, int onHeap);

    /* allocate a Value given its type */
    static Value *VariableAllocValueFromType(Interpreter *pc, ParseState *parser, ValueType *typ,
                                             int isLValue, Value *lValueFrom, int onHeap);

    /* allocate a Value either on the heap or the stack and copy
        its Value. handles overlapping data */
    static Value *VariableAllocValueAndCopy(Interpreter *pc, ParseState *parser, Value *fromValue,
                                            int onHeap);

    /* allocate a Value either on the heap or the stack from an
        existing AnyValue and type */
    static Value *VariableAllocValueFromExistingData(Interpreter *pc, ParseState *parser,
                                                     ValueType *typ, union AnyValue *fromValue, int isLValue,
                                                     Value *lValueFrom);

    /* allocate a Value either on the heap or the stack from an
        existing Value, sharing the Value */
    static Value *VariableAllocValueShared(Interpreter *pc, ParseState *parser,
                                           Value *fromValue);

    /* reallocate a variable so its data has a new size */
    static void VariableRealloc(Interpreter *pc, ParseState *parser, Value *fromValue,
                                int newSize);

    static int VariableScopeBegin(ParseState *parser, int *oldScopeID);

    static void VariableScopeEnd(ParseState *parser, int scopeID, int prevScopeID);

    static int VariableDefinedAndOutOfScope(Interpreter *pc, const char *ident);

    /* define a variable. ident must be registered */
    static Value *VariableDefine(Interpreter *pc, ParseState *parser, char *ident, Value *initValue,
                                 ValueType *typ, int makeWritable);

    /* define a variable. ident must be registered. If it's a redefinition
        from the same declaration don't throw an error */
    static Value *VariableDefineButIgnoreIdentical(ParseState *parser,
                                                   char *ident, ValueType *typ, int isStatic, int *firstVisit);

    /* check if a variable with a given name is defined. ident must be registered */
    static int VariableDefined(Interpreter *pc, const char *ident);

    /* get the Value of a variable. must be defined. ident must be registered */
    static void VariableGet(Interpreter *pc, ParseState *parser, const char *ident, Value **lVal);

    /* define a global variable shared with a platform global. ident will be registered */
    static void VariableDefinePlatformVar(Interpreter *pc, ParseState *parser, char *ident, ValueType *typ,
                                          AnyValue *fromValue, int isWritable);

    /* free and/or pop the top Value off the stack. Var must be
        the top Value on the stack! */
    static void VariableStackPop(ParseState *parser, Value *var);

    /* add a stack frame when doing a function call */
    static void VariableStackFrameAdd(ParseState *parser, const char *funcName,
                                      int numParams);

    /* remove a stack frame */
    static void VariableStackFramePop(ParseState *parser);

    /* get a string literal. assumes that ident is already
        registered. NULL if not found */
    static Value *VariableStringLiteralGet(Interpreter *pc, char *ident);

    /* define a string literal. assumes that ident is already registered */
    static void VariableStringLiteralDefine(Interpreter *pc, char *ident, Value *val);

    /* check a pointer for validity and dereference it for use */
    static void *VariableDereferencePointer(Value *pointerValue, Value **derefVal,
                                            int *derefOffset, ValueType **derefType, int *derefIsLValue);

private:
    //Interpreter *pc;
};

#endif //VARIABLE_H
